package com.cskaoyan.gateway.controller.shopping;


import com.cskaoyan.gateway.cache.CacheManager;
import com.cskaoyan.gateway.form.sekill.SekillForm;
import com.cskaoyan.gateway.form.shopping.PromoProductDetail;
import com.google.common.util.concurrent.RateLimiter;
import com.mall.commons.lock.DistributedLockException;
import com.mall.commons.result.ResponseData;
import com.mall.commons.result.ResponseUtil;
import com.mall.promo.PromoService;
import com.mall.promo.constant.PromoRetCode;
import com.mall.promo.dto.*;
import com.mall.user.annotation.Anoymous;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.user.dto.UsernameIdToken;
import com.mall.user.intercepter.TokenIntercepter;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @author: lsy
 * @class: SekillController
 */
@RestController
public class SekillController {

    @Reference(timeout = 30000, check = false, retries = 0)
    PromoService promoService;

    @Autowired
    CacheManager cacheManager;

    // 通过该工具，来实现令牌桶算法，实现限流
    RateLimiter rateLimiter;

    // 线程池
    ExecutorService executorService;

    @PostConstruct
    public void init() {
        // 创建一个每秒产生100个令牌的令牌桶
        rateLimiter = RateLimiter.create(50);

        executorService = Executors.newFixedThreadPool(50);
    }

    @GetMapping("/shopping/seckilllist")
    @Anoymous
    public ResponseData seckillList(Integer sessionId) {
        PromoInfoRequest promoInfoRequest = new PromoInfoRequest();
        promoInfoRequest.setSessionId(sessionId);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        String format = simpleDateFormat.format(new Date());

        promoInfoRequest.setYyyymmdd(format);
        PromoInfoResponse response = promoService.getPromoList(promoInfoRequest);
        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
            response.setSessionSeconds(10000L);
            return new ResponseUtil<>().setData(response);
        }
        return new ResponseUtil<>().setErrorMsg(response.getMsg());
    }

    @PostMapping("/shopping/promoProductDetail")
    @Anoymous
    public ResponseData promoProductDetail(@RequestBody PromoProductDetail promoProductDetail) {

        PromoProductDetailRequest promoProductDetailRequest = new PromoProductDetailRequest();
        promoProductDetailRequest.setProductId(promoProductDetail.getProductId());
        promoProductDetailRequest.setPsId(promoProductDetail.getPsId());
        PromoProductDetailResponse response = promoService.getPromoProductDetail(promoProductDetailRequest);
        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
            return new ResponseUtil<>().setData(response);
        }
        return new ResponseUtil<>().setErrorMsg(response.getMsg());

    }

    @PostMapping("/shopping/seckill")
    public ResponseData seckill(@RequestBody SekillForm sekillForm, HttpServletRequest request) {

        // 总体的请求限流(令牌桶来做)
        // 如果获取令牌成功，继续向下正常执行，需要等待一段时间
        rateLimiter.acquire();

        Long productId = sekillForm.getProductId();
        Long psId = Long.parseLong(sekillForm.getPsId());
        // 先判断有没有售罄
        String key = "stock_not_enough" + psId + "_" + productId;

         /*
              业务限流的工作
         */
        String s = cacheManager.checkCache(key);
        if (s != null && "notEnough".equals(s.trim())) {
            return new ResponseUtil<>().setErrorMsg("商品售罄");
        }

        UsernameIdToken usernameIdToken = (UsernameIdToken) request.getAttribute(TokenIntercepter.USER_INFO_KEY);
        long userId = usernameIdToken.getUserId();

        CreatePromoOrderRequest createPromoOrderRequest = new CreatePromoOrderRequest();
//        createPromoOrderRequest.setPromoPrice();
        createPromoOrderRequest.setAddressId(sekillForm.getAddressId());
        createPromoOrderRequest.setProductId(sekillForm.getProductId());
        createPromoOrderRequest.setPsId(Long.parseLong(sekillForm.getPsId()));
        createPromoOrderRequest.setUsername(sekillForm.getUserName());
        createPromoOrderRequest.setTel(sekillForm.getTel());
        createPromoOrderRequest.setStreetName(sekillForm.getStreetName());
        createPromoOrderRequest.setUserId(userId);

        // 对下游服务的调用放入线程池中来执行
        Future<CreatePromoOrderResponse> future = executorService.submit(new Callable<CreatePromoOrderResponse>() {

            @Override
            public CreatePromoOrderResponse call() throws Exception {
                return promoService.createPromoOrderInTransaction(createPromoOrderRequest);
            }
        });

        try {
            CreatePromoOrderResponse createPromoOrderResponse = future.get();
            if (PromoRetCode.SUCCESS.getCode().equals(createPromoOrderResponse.getCode())) {
                return new ResponseUtil<>().setData(createPromoOrderResponse);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


//        CreatePromoOrderResponse response = promoService.createPromoOrder(createPromoOrderRequest);
//        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
//            return new ResponseUtil<>().setData(null);
//        }
        return new ResponseUtil<>().setErrorMsg(SysRetCodeConstants.SYSTEM_ERROR.getMessage());

    }

    @PostMapping("/shopping/seckill2")
    public ResponseData seckill2(@RequestBody SekillForm sekillForm, HttpServletRequest request) {


        UsernameIdToken usernameIdToken = (UsernameIdToken) request.getAttribute(TokenIntercepter.USER_INFO_KEY);
        long userId = usernameIdToken.getUserId();

        CreatePromoOrderRequest createPromoOrderRequest = new CreatePromoOrderRequest();
//        createPromoOrderRequest.setPromoPrice();
        createPromoOrderRequest.setAddressId(sekillForm.getAddressId());
        createPromoOrderRequest.setProductId(sekillForm.getProductId());
        createPromoOrderRequest.setPsId(Long.parseLong(sekillForm.getPsId()));
        createPromoOrderRequest.setUsername(sekillForm.getUserName());
        createPromoOrderRequest.setTel(sekillForm.getTel());
        createPromoOrderRequest.setStreetName(sekillForm.getStreetName());
        createPromoOrderRequest.setUserId(userId);


        CreatePromoOrderResponse response = promoService.createPromoOrderInTransaction(createPromoOrderRequest);

        if (PromoRetCode.SUCCESS.getCode().equals(response.getCode())) {
            return new ResponseUtil<>().setData(response);
        }


        return new ResponseUtil<>().setErrorMsg(SysRetCodeConstants.SYSTEM_ERROR.getMessage());

    }
}
